package org.groupg.practice;


import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;

public class PerformanceComparison {
    // 测试参数
    private static final int PRODUCER_COUNT = 2;   // 生产者数量
    private static final int CONSUMER_COUNT = 2;   // 消费者数量
    private static final int MESSAGE_COUNT = 10_000_000; // 消息总数
    private static final int QUEUE_CAPACITY = 1024*1024;     // 队列容量

    public static void main(String[] args) throws InterruptedException {
        System.out.println("Starting performance comparison...");
        System.out.println("Producers: " + PRODUCER_COUNT + ", Consumers: " + CONSUMER_COUNT);
        System.out.println("Total messages: " + MESSAGE_COUNT);

        // 测试 JDK ArrayBlockingQueue
        BlockingQueue<Integer> jdkQueue = new ArrayBlockingQueue<>(QUEUE_CAPACITY);
        long jdkTime = testQueue(jdkQueue, "JDK ArrayBlockingQueue");

        // 测试 JCTools MpmcArrayQueue (多生产者多消费者)
        // 注意：根据生产者消费者数量，你也可以选择其他队列类型
        // 例如，如果是单生产者单消费者，使用SpscArrayQueue会更合适
        org.jctools.queues.MessagePassingQueue<Integer> jctoolsQueue =
                new org.jctools.queues.MpmcArrayQueue<>(QUEUE_CAPACITY);
        long jctoolsTime = testQueue(jctoolsQueue, "JCTools MpmcArrayQueue");

        // 输出结果对比
        System.out.println("\n========== RESULTS ==========");
        System.out.printf("JDK ArrayBlockingQueue: %,d ms%n", jdkTime);
        System.out.printf("JCTools MpmcArrayQueue: %,d ms%n", jctoolsTime);
        double improvement = (double) (jdkTime - jctoolsTime) / jdkTime * 100;
        System.out.printf("Performance improvement: %.2f%%%n", improvement);
    }

    private static long testQueue(BlockingQueue<Integer> queue, String queueType)
            throws InterruptedException {
        System.out.println("\n----- Testing " + queueType + " -----");
        long startTime = System.currentTimeMillis();

        CountDownLatch producerLatch = new CountDownLatch(PRODUCER_COUNT);
        CountDownLatch consumerLatch = new CountDownLatch(CONSUMER_COUNT);

        // 启动生产者
        int messagesPerProducer = MESSAGE_COUNT / PRODUCER_COUNT;
        for (int i = 0; i < PRODUCER_COUNT; i++) {
            final int producerId = i;
            new Thread(() -> {
                try {
                    for (int j = 0; j < messagesPerProducer; j++) {
                        int message = producerId * messagesPerProducer + j;
                        queue.put(message);
                    }
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
                producerLatch.countDown();
            }).start();
        }

        // 启动消费者
        int expectedPerConsumer = MESSAGE_COUNT / CONSUMER_COUNT;
        for (int i = 0; i < CONSUMER_COUNT; i++) {
            new Thread(() -> {
                int received = 0;
                while (received < expectedPerConsumer) {
                    try {
                        Integer item = queue.take();
                        if (item != null) {
                            received++;
                            // 模拟一些处理工作
                            if (item % 100000 == 0) {
                                System.out.print(".");
                            }
                        }
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                        break;
                    }
                }
                consumerLatch.countDown();
            }).start();
        }

        // 等待所有生产者和消费者完成
        producerLatch.await();
        consumerLatch.await();

        long endTime = System.currentTimeMillis();
        return endTime - startTime;
    }

    // 重载方法用于测试 JCTools 队列
    private static long testQueue(org.jctools.queues.MessagePassingQueue<Integer> queue,
                                 String queueType) throws InterruptedException {
        System.out.println("\n----- Testing " + queueType + " -----");
        long startTime = System.currentTimeMillis();

        CountDownLatch producerLatch = new CountDownLatch(PRODUCER_COUNT);
        CountDownLatch consumerLatch = new CountDownLatch(CONSUMER_COUNT);

        // 启动生产者
        int messagesPerProducer = MESSAGE_COUNT / PRODUCER_COUNT;
        for (int i = 0; i < PRODUCER_COUNT; i++) {
            final int producerId = i;
            new Thread(() -> {
                for (int j = 0; j < messagesPerProducer; j++) {
                    int message = producerId * messagesPerProducer + j;
                    // JCTools 队列通常使用 offer 和 poll
                    while (!queue.offer(message)) {
                        // 队列满时重试
                        Thread.yield();
                    }
                }
                producerLatch.countDown();
            }).start();
        }

        // 启动消费者
        int expectedPerConsumer = MESSAGE_COUNT / CONSUMER_COUNT;
        for (int i = 0; i < CONSUMER_COUNT; i++) {
            new Thread(() -> {
                int received = 0;
                while (received < expectedPerConsumer) {
                    Integer item = queue.poll();
                    if (item != null) {
                        received++;
                        // 模拟一些处理工作
                        if (item % 100000 == 0) {
                            System.out.print(".");
                        }
                    } else {
                        // 队列空时短暂让出CPU
                        Thread.yield();
                    }
                }
                consumerLatch.countDown();
            }).start();
        }

        // 等待所有生产者和消费者完成
        producerLatch.await();
        consumerLatch.await();

        long endTime = System.currentTimeMillis();
        return endTime - startTime;
    }
}